package com.ruoyi.manufacturer.common;

import com.ruoyi.alarm.domain.AlarmData;
import com.ruoyi.alarm.domain.AlarmRule;
import com.ruoyi.alarm.domain.AlarmType;
import com.ruoyi.alarm.domain.AlarmWarning;
import com.ruoyi.alarm.service.IAlarmDataService;
import com.ruoyi.alarm.service.IAlarmRuleService;
import com.ruoyi.alarm.service.IAlarmTypeService;
import com.ruoyi.alarm.service.IAlarmWarningService;
import com.ruoyi.base.domain.BaseDevice;
import com.ruoyi.base.service.IBaseDeviceService;
import com.ruoyi.common.consts.AlarmTypeEnum;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.manufacturer.*;
import com.ruoyi.third.domain.ThirdEvent;
import com.ruoyi.third.service.IThirdEventService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * 告警处理工具
 */
@Service
@Slf4j
public class AlarmHandler{
    private static final String CACHE_MAP = "alarm_data_real";
    //10分钟之内不记录重复监测值
    private static final int SAME_DATA_PERIOD = 10 * 60 * 1000;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    protected IThirdEventService thirdEventService;
    @Autowired
    protected IBaseDeviceService baseDeviceService;
    @Autowired
    protected IAlarmWarningService alarmWarningService;
    @Autowired
    protected IAlarmTypeService alarmTypeService;
    @Autowired
    protected IAlarmRuleService alarmRuleService;
    @Autowired
    protected IAlarmDataService alarmDataService;

    /**
     * 触发告警规则
     *
     * @param alarmWarning 告警信息
     * @param baseDevice 告警设备
     * @return 结果
     */
    @Async("threadPoolTaskExecutor")
    public int triggerAlarmRule(AlarmWarning alarmWarning, BaseDevice baseDevice){
        List<AlarmRule> list = alarmRuleService.selectAlarmRuleByDevice(baseDevice.getId(), alarmWarning.getAlarmType());
        if(list == null || list.isEmpty()){
            return 0;
        }
        AsyncManager.me().delay(()->{
            ControlVo controlVo = ControlVo.create(null, ControlCommand.START.getCode());
            for(AlarmRule rule:list){
                String[] deviceIds = rule.getTriggerDevice().split(",");
                for(String deviceId:deviceIds) {
                    BaseDevice device = baseDeviceService.selectBaseDeviceById(Long.parseLong(deviceId));
                    if(baseDevice != null){
                        controlVo.setDeviceId(device.getId());
                        controlVo.setDevice(device);
                        triggerDevice(controlVo);
                    }
                }
            }
        }, 100);
        return list.size();
    }

    /**
     * 触发启动设备
     * @param controlVo
     */
    public void triggerDevice(ControlVo controlVo){
        IPlatform platform = PlatformTask.getHandler(controlVo.getDevice().getPfCode());
        if(platform == null){
            log.error("不支持的反控设备: {}", controlVo.getDevice());
            return;
        }

        platform.control(controlVo);
    }

    /**
     * 默认的处理告警信息流程
     * @param alarm 告警消息
     * @param device 告警设备
     * @return AlarmWarning
     */
    public AlarmWarning processAlarm(MessageVo.Alarm alarm, BaseDevice device){
        if(alarm.getAlarmTime() == null){
            alarm.setAlarmTime(new Date());
        }
        ThirdEvent thirdEvent = thirdEventService.selectThirdEventByCode(alarm.getEventCode(), device.getPfCode());
        if(thirdEvent == null){
            thirdEvent = thirdEventService.autoEvent(alarm.getEventCode(), alarm.getEventDesc(), device.getPfCode());
        }

        //自动注册告警类型
        if(thirdEvent == null){
            throw new ServiceException("不支持告警事件");
        }

        //告警类型
        AlarmType alarmType = alarmTypeService.selectAlarmType(thirdEvent.getAlarmType());
        //撤销
        if(thirdEvent.getAlarmState().equalsIgnoreCase(ThirdEvent.STATE_CANCEL)){
            alarmWarningService.repealAlarmWarning(device.getId(), thirdEvent.getAlarmType());
            //恢复设备状态
            if(alarmType.getBigType().equalsIgnoreCase(AlarmType.TYPE_FAULT)){
                device.setRunStatus(BaseDevice.RUN_NORMAL);
                baseDeviceService.updateBaseDeviceStatus(device);
            }
            return createAlarm(alarm, thirdEvent, device);
        }else {
            //新告警
            AlarmWarning alarmWarning = createAlarm(alarm, thirdEvent, device);
            alarmWarningService.insertAlarmWarning(alarmWarning);

            //故障告警，更新设备为离线或者故障状态
            alarmWarning.setType(alarmType);
            if (alarmType.getAlarmCode().equalsIgnoreCase(AlarmTypeEnum.OFFLINE.getCode())) {
                device.setRunStatus(BaseDevice.RUN_OFFLINE);
                baseDeviceService.updateBaseDeviceStatus(device);
            } else if (alarmType.getBigType().equalsIgnoreCase(AlarmType.TYPE_FAULT)) {
                device.setRunStatus(BaseDevice.RUN_FAULT);
                baseDeviceService.updateBaseDeviceStatus(device);
            }
            return alarmWarning;
        }
    }

    /**
     * 创建告警的基本信息
     * @param alarm 告警
     * @param event 事件
     * @param device 设备
     * @return AlarmWarning
     */
    public AlarmWarning createAlarm(MessageVo.Alarm alarm, ThirdEvent event, BaseDevice device){
        AlarmWarning alarmWarning = new AlarmWarning();
        alarmWarning.setAlarmType(event.getAlarmType());
        alarmWarning.setAlarmCode(alarm.getId());
        alarmWarning.setAlarmTime(alarm.getAlarmTime() == null ? new Date() : alarm.getAlarmTime());
        alarmWarning.setDeviceCode(device.getCode());
        alarmWarning.setDeviceId(device.getId());
        alarmWarning.setDeptId(device.getDeptId());
        alarmWarning.setDeviceSysId(device.getSysId());
        alarmWarning.setDeviceTypeId(device.getTypeId());
        alarmWarning.setPosition(device.getPosition());
        alarmWarning.setHandleStatus("0");
        alarmWarning.setImagePath(alarm.getAlarmImg());
        alarmWarning.setVideoPath(alarm.getAlarmVideo());
        alarmWarning.setComment(alarm.getEventDesc());
        alarmWarning.setEventCode(alarm.getEventCode());
        return alarmWarning;
    }

    /**
     * 处理监测数据,温度/温度/电压/电流/光亮等
     * @param business 数据
     * @param device 设备
     * @return
     */
    public boolean processData(MessageVo.Business business, BaseDevice device){
        if(business.getAnalogValue() == null){
            return false;
        }

        //判断是否有近期的相同监测数据
        String key = device.getId()+business.getAnalogName();
        AlarmData old = redisCache.getCacheMapValue(CACHE_MAP, key);
        if(old != null
                && business.getTime().getTime() - old.getMonitorTime().getTime() < SAME_DATA_PERIOD
                && old.getAnalogValue().compareTo(business.getAnalogValue()) == 0){
            return true;
        }

        //新监测数据
        AlarmData alarmData = new AlarmData();
        alarmData.setAnalogName(business.getAnalogName());
        alarmData.setDeptId(device.getDeptId());
        alarmData.setDeviceId(device.getId());
        alarmData.setDeviceCode(device.getCode());
        alarmData.setDeviceType(device.getTypeName());
        alarmData.setPosition(device.getPosition());
        alarmData.setAnalogType(business.getAnalogType());
        alarmData.setAnalogValue(business.getAnalogValue());
        alarmData.setMonitorTime(business.getTime());
        alarmData.setThresholdHigh(business.getThresholdHigh());
        alarmData.setThresholdLow(business.getThresholdLow());
        if(StringUtils.isEmpty(business.getContent())){
            alarmData.setContent(business.getAnalogName() + " " + business.getAnalogValue() + business.getAnalogType());
        }else{
            alarmData.setContent(business.getContent());
        }
        alarmData.setDataStatus("1");
        if(alarmData.getThresholdHigh() != null && alarmData.getAnalogValue().compareTo(alarmData.getThresholdHigh()) > 0){
            alarmData.setDataStatus("2");
        }
        if(alarmData.getThresholdLow() != null && alarmData.getAnalogValue().compareTo(alarmData.getThresholdLow()) == 0){
            alarmData.setDataStatus("0");
        }

        alarmDataService.insertAlarmData(alarmData);
        redisCache.setCacheMapValue(CACHE_MAP, key, alarmData);
        return true;
    }
}
